/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { HvigorNode } from '@ohos/hvigor';
import { OhosHapContext, Target } from '@ohos/hvigor-ohos-plugin';
import { ITask, Logger, TurboTransJsonPluginOptions, ConfigManager, TempSerializerGenerator } from '../core';
import { TargetContextImpl } from './interfaces/impl/TargetContext';
import { ModuleContextImpl } from './interfaces/impl/ModuleContext';
import { IModuleContext } from './interfaces/IModuleContext';
import { CodeProcessingTask } from './tasks/CodeProcessingTask';
import { CleanTask } from './tasks/CleanTask';
import { SyncTask } from './tasks/SyncTask';
import { WatchTask } from './tasks/WatchTask';
import SerializationPathUtil from '../core/utils/SerializationPathUtil';
import { CustomError, ErrorCodes } from '../core/utils/CustomError';
import { TaskConstants } from './constants/TaskConstants';
import { TsMorphUtil } from '../core/utils/TsMorphUtil';
import { CustomTypeAnalyzer } from '../core/analyzers/CustomTypeAnalyzer';
import { SendableMergeabilityRegistry } from '../core/analyzers/SendableMergeabilityRegistry';

export class JSONExecuteController {
  private readonly node: HvigorNode;
  private readonly options: TurboTransJsonPluginOptions;
  tasks: Set<ITask> = new Set();

  constructor(node: HvigorNode, options: TurboTransJsonPluginOptions) {
    this.node = node;
    this.options = options;
  }

  execute(): void {
    // 设置导入重写配置
    const configManager = ConfigManager.getInstance();
    configManager.setConfig(this.options);

    // 在nodesEvaluated之后才能拿到moduleContext
    const moduleContext: OhosHapContext = this.node.getContext(this.node.getAllPluginIds()[0]);

    const context = new ModuleContextImpl(this.node, moduleContext);

    context.initScanFiles(this.options.scanDir);

    // 1. 初始化任务
    this.initTasks();

    // 2. 按照target注册任务
    moduleContext.targets((target: Target) => {
      this.registerHvigorTasks(target, context);
    });
  }

  compile(): void {
    // 编译结束后的清理逻辑由clean任务处理
  }

  private initTasks() {
    this.tasks.add(new CodeProcessingTask());
    this.tasks.add(new CleanTask());
    this.tasks.add(new SyncTask());
    this.tasks.add(new WatchTask());
  }

  private taskCleanUp(): void {
    const sourceFiles = TsMorphUtil.getProject().getSourceFiles();
    Logger.info(`code analysis Clearing ${sourceFiles.length} source files...`);
    sourceFiles.forEach((sourceFile) => {
      TsMorphUtil.getProject().removeSourceFile(sourceFile);
    });
    CustomTypeAnalyzer.getInstance().clearCache();
    SendableMergeabilityRegistry.clear();
  }

  private registerHvigorTasks(target: Target, context: IModuleContext) {
    const targetContext = new TargetContextImpl(target, context);
    this.tasks.forEach((task) => {
      this.node.registerTask({
        name: task.taskName,
        run: async () => {
          try {
            Logger.info(`${task.taskName} run`);
            TempSerializerGenerator.getInstance().init(targetContext);
            const result = task.run(targetContext);
            // clean任务不需要生成序列化器
            if (task.taskName !== TaskConstants.CLEAN_TASK) {
              TempSerializerGenerator.getInstance().saveFile();
            }
            if (result instanceof Promise) {
              await result;
            }
            if (task.taskName === TaskConstants.SYNC_TASK || task.taskName === TaskConstants.CODE_PROCESSING_TASK) {
              this.taskCleanUp();
            }
            Logger.info(`${task.taskName} end`);
          } catch (error) {
            if (error instanceof CustomError) {
              Logger.error(`Error: ${error.constructor.name}: ${error.code} ${error.message}\n${error.stack}`);
            } else {
              const err = error as Error;
              Logger.error(`Error: ${err.constructor.name}: ${ErrorCodes.INTERNAL_ERROR} ${err.message}\n${err.stack}`);
            }
            this.taskCleanUp();
            throw new Error('serialization execute failed');
          }
        },
        dependencies: task.dependencies.map((dep) => `${target.getTargetName()}@${dep}`),
        postDependencies: task.postDependencies.map((dep) => `${target.getTargetName()}@${dep}`)
      });
    });

    const cleanTask = this.node.getTaskByName('clean');
    if (cleanTask) {
      cleanTask.beforeRun(() => {
        const generatedRootDir = targetContext.getOutputRoot();

        if (SerializationPathUtil.exist(generatedRootDir)) {
          Logger.info(`Clean up the generated directory: ${generatedRootDir}`);
          SerializationPathUtil.rmSync(generatedRootDir, { recursive: true, force: true });
        }
      });
    }
  }
}
